/*
 * Copyright (c) 2015-2018, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== rfEasyLinkRx.c ========
 */
/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/runtime/Assert.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Clock.h>

/* TI-RTOS Header files */
#include <ti/drivers/PIN.h>

/* Board Header files */
#include "Board.h"

/* EasyLink API Header files */
#include "easylink/EasyLink.h"
/********************************************************************************/
#include "config.h"
#include "soft_timer.h"
/********************************************************************************/
/***** Defines *****/

/* Undefine to remove async mode */
#define RFEASYLINKRX_ASYNC
#define RFEASYLINKTX_ASYNC

#define RFEASYLINKRXTX_TASK_STACK_SIZE    2048
#define RFEASYLINKRXTX_TASK_PRIORITY      2

/***** Variable declarations *****/
static Task_Params rxtxTaskParams;
Task_Struct rxtxTask;    /* not static so you can see in ROV */
static uint8_t rxtxTaskStack[RFEASYLINKRXTX_TASK_STACK_SIZE];

bool TxSendFlag = FALSE;

#ifdef RFEASYLINKRX_ASYNC
static Semaphore_Handle rxDoneSem;
#endif
#ifdef RFEASYLINKTX_ASYNC
static Semaphore_Handle txDoneSem;
#endif
#define RFEASYLINKTX_BURST_SIZE         64
#define RFEASYLINKTXPAYLOAD_LENGTH      128

/***** Function definitions *****/
#ifdef RFEASYLINKRX_ASYNC
void rxDoneCb(EasyLink_RxPacket * rxPacket, EasyLink_Status status)
{
    if (status == EasyLink_Status_Success) {
        Write_RingBuff(&rf433_buff, &rxPacket->payload[2], rxPacket->len -2);
    }
    else if(status == EasyLink_Status_Aborted) {
    }
    else {
    }
    Semaphore_post(rxDoneSem);
}
#endif
/***** Function definitions *****/
#ifdef RFEASYLINKTX_ASYNC
void txDoneCb(EasyLink_Status status)
{
    if (status == EasyLink_Status_Success) {
    }
    else if(status == EasyLink_Status_Aborted) {
    }
    else {
    }
    TxSendFlag = FALSE;
    Semaphore_post(txDoneSem);
}
#endif
void easylinkpacksend(uint8_t* packet, uint8_t len)
{
    TxSendFlag = TRUE;
    uint8_t txBurstSize = 0;
    uint32_t absTime;
    static uint16_t seqNumber;

    EasyLink_TxPacket txPacket =  { {0}, 0, 0, {0} };

    /* Create packet with incrementing sequence number and random payload */
    txPacket.payload[0] = (uint8_t)(seqNumber >> 8);
    txPacket.payload[1] = (uint8_t)(seqNumber++);
    uint8_t i;
    if(len >= RFEASYLINKTXPAYLOAD_LENGTH)
    {
        len = RFEASYLINKTXPAYLOAD_LENGTH;
    }
    for (i = 0; i < len; i++)
    {
      txPacket.payload[i + 2] = packet[i];
    }

    txPacket.len = len + 2;
    /*
     * Address filtering is enabled by default on the Rx device with the
     * an address of 0xAA. This device must set the dstAddr accordingly.
     */
    txPacket.dstAddr[0] = 0xaa;

    /* Add a Tx delay for > 500ms, so that the abort kicks in and brakes the burst */
    if(EasyLink_getAbsTime(&absTime) != EasyLink_Status_Success)
    {
        // Problem getting absolute time
    }
    if(txBurstSize++ >= RFEASYLINKTX_BURST_SIZE)
    {
      /* Set Tx absolute time to current time + 1s */
      txPacket.absTime = absTime + EasyLink_ms_To_RadioTime(1000);
      txBurstSize = 0;
    }
    /* Else set the next packet in burst to Tx in 100ms */
    else
    {
      /* Set Tx absolute time to current time + 100ms */
      txPacket.absTime = absTime + EasyLink_ms_To_RadioTime(100);
    }

    EasyLink_transmitAsync(&txPacket, txDoneCb);
    /* Wait 300ms for Tx to complete */
    if(Semaphore_pend(txDoneSem, (300000 / Clock_tickPeriod)) == FALSE)
    {
        /* TX timed out, abort */
        if(EasyLink_abort() == EasyLink_Status_Success)
        {
            /*
             * Abort will cause the txDoneCb to be called and the txDoneSem
             * to be released, so we must consume the txDoneSem
             */
           Semaphore_pend(txDoneSem, BIOS_WAIT_FOREVER);
        }
    }
}
static void rfEasyLinkRxTxFnx(UArg arg0, UArg arg1)
{
#ifndef RFEASYLINKRX_ASYNC
    EasyLink_RxPacket rxPacket = {0};
#endif
    DataBuff cache;
#ifdef RFEASYLINKRX_ASYNC
    /* Create a semaphore for Async*/
    Semaphore_Params paramsRx;
    Error_Block ebRx;

    /* Init params */
    Semaphore_Params_init(&paramsRx);
    Error_init(&ebRx);

    /* Create semaphore instance */
    rxDoneSem = Semaphore_create(0, &paramsRx, &ebRx);
    if(rxDoneSem == NULL)
    {
        System_abort("Semaphore creation failed");
    }

#endif //RFEASYLINKRX_ASYNC
#ifdef RFEASYLINKTX_ASYNC
    /* Create a semaphore for Async */
    Semaphore_Params paramsTx;
    Error_Block ebTx;

    /* Init params */
    Semaphore_Params_init(&paramsTx);
    Error_init(&ebTx);

    /* Create semaphore instance */
    txDoneSem = Semaphore_create(0, &paramsTx, &ebTx);
    if(txDoneSem == NULL)
    {
        System_abort("Semaphore creation failed");
    }

#endif //TX_ASYNC
    // Initialize the EasyLink parameters to their default values
    EasyLink_Params easyLink_params;
    EasyLink_Params_init(&easyLink_params);

    /*
     * Initialize EasyLink with the settings found in easylink_config.h
     * Modify EASYLINK_PARAM_CONFIG in easylink_config.h to change the default
     * PHY
     */
    if(EasyLink_init(&easyLink_params) != EasyLink_Status_Success)
    {
        System_abort("EasyLink_init failed");
    }

    /*
     * If you wish to use a frequency other than the default, use
     * the following API:
     * EasyLink_setFrequency(868000000);
     */

    while(1) {
        if(TxSendFlag != TRUE)
        {
#ifdef RFEASYLINKRX_ASYNC
            EasyLink_receiveAsync(rxDoneCb, 0);
            /* Wait 300ms for Rx */
            if(Semaphore_pend(rxDoneSem, (30000 / Clock_tickPeriod)) == FALSE)
            {
                /* RX timed out abort */
                if(EasyLink_abort() == EasyLink_Status_Success)
                {
                   /* Wait for the abort */
                   Semaphore_pend(rxDoneSem, BIOS_WAIT_FOREVER);
                }
            }
#endif //RX_ASYNC
        }
        if(0 == Read_RingBuff((RingBuff*) &uart_buff, &cache)) {
//            UART_write(uart, &cache.data, cache.len);
            easylinkpacksend(&cache.data, cache.len);
        }
    }
}

void rxtxTask_init(void) {
    Task_Params_init(&rxtxTaskParams);
    rxtxTaskParams.stackSize = RFEASYLINKRXTX_TASK_STACK_SIZE;
    rxtxTaskParams.priority = RFEASYLINKRXTX_TASK_PRIORITY;
    rxtxTaskParams.stack = &rxtxTaskStack;
    rxtxTaskParams.arg0 = (UInt)1000000;

    Task_construct(&rxtxTask, rfEasyLinkRxTxFnx, &rxtxTaskParams, NULL);
}

/*
 *  ======== main ========
 */
int main(void)
{
    /* Call driver init functions */
    Board_initGeneral();
    CPUdelay(2000000 * 12);

    led_ini();
    timer_ini();
    uart_ini();
    adc_simple_ini();
    softTimer_Init();
    softTimer_Start(TIMER0, MODE_PERIODIC, 200, TIM0_CB, NULL, 0);
    softTimer_Start(TIMER1, MODE_PERIODIC, 4000, TIM1_CB, NULL, 0);
//    softTimer_Start(TIMER2, MODE_PERIODIC, 5, TIM2_CB, NULL, 0);

    userFuncTask_init();
    rxtxTask_init();
    /* Start BIOS */
    BIOS_start();

    return (0);
}
